package com.yyfax.pay.third.facade.quickpay;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.security.SignatureException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang.NotImplementedException;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import com.yyfax.commons.json.JacksonUtil;
import com.yyfax.framework.yyfax.enums.RspCodeEnum;
import com.yyfax.pay.common.constants.PayConstants;
import com.yyfax.pay.common.enums.PayModeEnum;
import com.yyfax.pay.common.enums.PayRspCodeEnum;
import com.yyfax.pay.common.enums.PayTypeEnum;
import com.yyfax.pay.common.enums.PaymentEnum;
import com.yyfax.pay.common.exception.YYPayException;
import com.yyfax.pay.common.util.CommonIdUtils;
import com.yyfax.pay.common.util.QuickPayEncodeCerUtil;
import com.yyfax.pay.order.model.vo.PayBusiIdVO;
import com.yyfax.pay.third.model.to.quickpay.AuthenticationQuickPayContent;
import com.yyfax.pay.third.model.to.quickpay.AuthenticationQuickPayParams;
import com.yyfax.pay.third.model.to.quickpay.NotifyQuickPayContent;
import com.yyfax.pay.third.model.to.quickpay.NotifyQuickPayParams;
import com.yyfax.pay.third.model.to.quickpay.PayOrderQuickPayContent;
import com.yyfax.pay.third.model.to.quickpay.PayOrderQuickPayParams;
import com.yyfax.pay.third.model.to.quickpay.QueryOrderQuickPayContent;
import com.yyfax.pay.third.model.to.quickpay.QueryOrderQuickPayParams;
import com.yyfax.pay.third.model.to.quickpay.QuickPayConstant;
import com.yyfax.pay.third.model.to.quickpay.SendAuthenticationVerifyCodeQuickPayContent;
import com.yyfax.pay.third.model.to.quickpay.SendAuthenticationVerifyCodeQuickPayParams;
import com.yyfax.pay.third.model.to.quickpay.SendVerifyCodeQuickPayContent;
import com.yyfax.pay.third.model.to.quickpay.SendVerifyCodeQuickPayParams;
import com.yyfax.pay.third.model.to.quickpay.xml.TxnMsgContent;
import com.yyfax.pay.third.model.to.yyfax.AuthenticationYYContent;
import com.yyfax.pay.third.model.to.yyfax.AuthenticationYYParams;
import com.yyfax.pay.third.model.to.yyfax.OrderNotifyContent;
import com.yyfax.pay.third.model.to.yyfax.OrderReturnContent;
import com.yyfax.pay.third.model.to.yyfax.PayOrderYYContent;
import com.yyfax.pay.third.model.to.yyfax.PayOrderYYParams;
import com.yyfax.pay.third.model.to.yyfax.PayReturnParams;
import com.yyfax.pay.third.model.to.yyfax.PayWebFormContent;
import com.yyfax.pay.third.model.to.yyfax.PayoutBatchOrderYYContent;
import com.yyfax.pay.third.model.to.yyfax.PayoutBatchOrderYYParams;
import com.yyfax.pay.third.model.to.yyfax.PayoutOrderYYContent;
import com.yyfax.pay.third.model.to.yyfax.PayoutOrderYYParams;
import com.yyfax.pay.third.model.to.yyfax.QueryBatchPayoutOrderCheckYYContent;
import com.yyfax.pay.third.model.to.yyfax.QueryBatchPayoutOrderCheckYYParams;
import com.yyfax.pay.third.model.to.yyfax.QueryBatchPayoutOrderYYContent;
import com.yyfax.pay.third.model.to.yyfax.QueryBatchPayoutOrderYYParams;
import com.yyfax.pay.third.model.to.yyfax.QueryCardBinContent;
import com.yyfax.pay.third.model.to.yyfax.QueryCardBinParams;
import com.yyfax.pay.third.model.to.yyfax.QueryPayOrderYYContent;
import com.yyfax.pay.third.model.to.yyfax.QueryPayOrderYYParams;
import com.yyfax.pay.third.model.to.yyfax.QueryPayoutOrderYYContent;
import com.yyfax.pay.third.model.to.yyfax.QueryPayoutOrderYYParams;
import com.yyfax.pay.third.model.to.yyfax.SendAuthenticationVerifyCodeYYContent;
import com.yyfax.pay.third.model.to.yyfax.SendAuthenticationVerifyCodeYYParams;
import com.yyfax.pay.third.model.to.yyfax.SendVerifyCodeYYContent;
import com.yyfax.pay.third.model.to.yyfax.SendVerifyCodeYYParams;
import com.yyfax.pay.third.model.to.yyfax.WebFormYYContent;
import com.yyfax.pay.third.model.to.yyfax.WebFormYYParams;
import com.yyfax.pay.third.service.PayInfoConstantService;
import com.yyfax.pay.third.service.ThirdPayService;
import com.yyfax.pay.third.service.TransformService;

/**
 * 快钱API接口外观
 * 
 * @author xiemh
 * @date 2017-04-11 16:49:08
 * @since v1.0.0
 */
public class QuickPayFacade extends ThirdPayService {
	private Logger logger = LoggerFactory.getLogger(getClass());

	@Resource(name = "quickPayTransformService")
	private TransformService transformService;

	@Resource
	private QuickPayApi quickPayApi;

	// @Autowired
	// private PayOrderService payOrderService;

	@Autowired
	private PayInfoConstantService quickPayInfoUtil;

	@Autowired
	private PayConstants payConstants;

	@PostConstruct
	private void init() {
		this.facadeName = "快钱";
	}

	@Override
	public SendVerifyCodeYYContent sendVerifyCode(SendVerifyCodeYYParams req) throws Exception {
		SendVerifyCodeYYContent content = null;
		SendVerifyCodeQuickPayParams quickPayParams = null;
		SendVerifyCodeQuickPayContent sendVerifyCodeQuickPayContent = null;
		try {
			quickPayParams = transformService.transformSendVerifyCodeParams(req);
			quickPayParams.validate();
			sendVerifyCodeQuickPayContent = quickPayApi.sendVerifyCode(quickPayParams);
			content = transformService.transformSendVerifyCodeContent(sendVerifyCodeQuickPayContent);
		} catch (YYPayException e) {
			content = new SendVerifyCodeYYContent();
			content.setResultCode(e.getCode());
			content.setResultMsg(e.getMessage());
			logger.info("发送支付验证码-发生异常,req:{},exception:{}", JacksonUtil.noemptyMapper.toJson(req), e);
		} catch (Exception e) {
			content = new SendVerifyCodeYYContent();
			content.setResultCode(PayRspCodeEnum.PAY_CODE_GET_PAY_VERIFY_CODE_FAIL.getValue());
			content.setResultMsg("发送支付验证码失败。");
			logger.info("发送支付验证码-发生异常,req:{},exception:{}", JacksonUtil.noemptyMapper.toJson(req), e);
		}

		// 返回请求体、返回体、请求连接
		if (quickPayParams != null) {
			content.setReqUrl(quickPayParams.getReqUrl());
			content.setReqContent(quickPayParams.getReqContent());
			content.setRspContent(sendVerifyCodeQuickPayContent.getRspContent());
		}
		return content;
	}

	@Override
	public QueryPayOrderYYContent queryOrder(QueryPayOrderYYParams req) throws Exception {
		QueryPayOrderYYContent content = null;
		QueryOrderQuickPayParams quickPayParams = null;
		QueryOrderQuickPayContent queryOrderQuickPayContent = null;
		try {
			quickPayParams = transformService.transformQueryPayOrderParams(req);
			quickPayParams.validate();
			queryOrderQuickPayContent = quickPayApi.queryOrder(quickPayParams);
			content = transformService.transformQueryPayOrderContent(queryOrderQuickPayContent);
		} catch (YYPayException e) {
			logger.info("查询订单-发生异常,req:{},exception:{}", JacksonUtil.noemptyMapper.toJson(req), e);
			content = new QueryPayOrderYYContent();
			content.setResultCode(e.getCode());
			content.setResultMsg(e.getMessage());
		} catch (Exception e) {
			logger.info("查询订单-发生异常,req:{},exception:{}", JacksonUtil.noemptyMapper.toJson(req), e);
			content = new QueryPayOrderYYContent();
			content.setResultCode(PayRspCodeEnum.PAY_CODE_QUERY_ORDER_FAIL.getValue());
			content.setResultMsg("查询订单失败。");
		}

		// 返回请求体、返回体、请求连接
		if (quickPayParams != null) {
			content.setReqUrl(quickPayParams.getReqUrl());
			content.setReqContent(quickPayParams.getReqContent());
			content.setRspContent(queryOrderQuickPayContent.getRspContent());
		}
		return content;
	}

	@Override
	public SendAuthenticationVerifyCodeYYContent sendAuthenticationVerifyCode(SendAuthenticationVerifyCodeYYParams req) throws Exception {
		SendAuthenticationVerifyCodeYYContent content = null;
		SendAuthenticationVerifyCodeQuickPayParams quickPayParams = null;
		SendAuthenticationVerifyCodeQuickPayContent sendAuthenticationVerifyCode = null;
		try {
			quickPayParams = transformService.transformSendAuthenticationVerifyCodeParams(req);
			quickPayParams.validate();
			sendAuthenticationVerifyCode = quickPayApi.sendAuthenticationVerifyCode(quickPayParams);
			content = transformService.transformSendAuthenticationVerifyCodeContent(sendAuthenticationVerifyCode);
			return content;
		} catch (YYPayException e) {
			logger.info("获取鉴权验证码-发生异常,req:{},exception:{}", JacksonUtil.noemptyMapper.toJson(req), e);
			content = new SendAuthenticationVerifyCodeYYContent();
			content.setResultCode(e.getCode());
			content.setResultMsg(e.getMessage());
		} catch (Exception e) {
			logger.info("获取鉴权验证码-发生异常,req:{},exception:{}", JacksonUtil.noemptyMapper.toJson(req), e);
			content = new SendAuthenticationVerifyCodeYYContent();
			content.setResultCode(PayRspCodeEnum.PAY_CODE_GET_AUTH_VERIFY_CODE_FAIL.getValue());
			content.setResultMsg("获取鉴权验证码失败。");
		}

		return content;
	}

	@Override
	public AuthenticationYYContent authentication(AuthenticationYYParams req) throws Exception {
		AuthenticationYYContent content = null;
		AuthenticationQuickPayParams quickPayParams = null;
		AuthenticationQuickPayContent authenticationContent = null;
		try {

			quickPayParams = transformService.transformAuthenticationParams(req);
			quickPayParams.validate();
			authenticationContent = quickPayApi.authentication(quickPayParams);
			content = transformService.transformAuthenticationContent(authenticationContent);
		} catch (YYPayException e) {
			logger.info("鉴权-发生异常,req:{},exception:{}", JacksonUtil.noemptyMapper.toJson(req), e);
			content = new AuthenticationYYContent();
			content.setResultCode(e.getCode());
			content.setResultMsg(e.getMessage());
		} catch (Exception e) {
			logger.info("鉴权-发生异常,req:{},exception:{}", JacksonUtil.noemptyMapper.toJson(req), e);
			content = new AuthenticationYYContent();
			content.setResultCode(PayRspCodeEnum.PAY_CODE_AUTH_FAIL.getValue());
			content.setResultMsg("鉴权失败。");
		}

		return content;
	}

	@Override
	public PayOrderYYContent payOrder(PayOrderYYParams req) throws Exception {
		PayOrderYYContent content = null;
		PayOrderQuickPayParams quickPayParams = null;
		PayOrderQuickPayContent payOrderContent = null;
		try {
			quickPayParams = transformService.transformPayOrdeParams(req);
			quickPayParams.validate();
			payOrderContent = quickPayApi.payOrder(quickPayParams);
			content = transformService.transformPayOrdeContent(payOrderContent);
		} catch (YYPayException e) {
			logger.info("支付-发生异常,req:{},exception:{}", JacksonUtil.noemptyMapper.toJson(req), e);
			content = new PayOrderYYContent();
			content.setResultCode(e.getCode());
			content.setResultMsg(e.getMessage());
		} catch (Exception e) {
			logger.info("支付-发生异常,req:{},exception:{}", JacksonUtil.noemptyMapper.toJson(req), e);
			content = new PayOrderYYContent();
			content.setResultCode(PayRspCodeEnum.PAY_CODE_PAY_FAIL.getValue());
			content.setResultMsg("支付失败。");
		}

		// 返回请求体、返回体、请求连接
		if (quickPayParams != null) {
			content.setReqUrl(quickPayParams.getReqUrl());
			content.setReqContent(quickPayParams.getReqContent());
			content.setRspContent(payOrderContent.getRspContent());
		}
		return content;
	}

	@Override
	public OrderNotifyContent transformPayOrderNotify(HttpServletRequest request) throws Exception {

		OrderNotifyContent content = new OrderNotifyContent();
		try {
			// 读取异步同步请求参数
			StringBuilder callBackMsg = new StringBuilder();
			try (InputStream is = request.getInputStream()) {
				try (BufferedReader in = new BufferedReader(new InputStreamReader(is, "UTF-8"))) {
					String line = in.readLine();
					while (StringUtils.isNotBlank(line)) {
						callBackMsg.append(line);
						line = in.readLine();
					}
				}
			} catch (Exception e) {
				logger.info("快钱异步回调 |解析报文出错", e);
				throw new YYPayException(PayRspCodeEnum.PAY_CODE_PAY_FAIL.getValue(), "快钱异步回调 |解析报文出错");
			}
			if (StringUtils.isBlank(callBackMsg)) {
				throw new YYPayException(PayRspCodeEnum.PAY_CODE_PAY_FAIL.getValue(), "快钱异步回调 |消息体为空");
			}

			// 请求报文
			content.setReqContent(callBackMsg.toString());

			logger.info("快钱异步回调 | 请求报文：{}", callBackMsg);

			// 将请求报文转换为实体类
			NotifyQuickPayParams quickPayParams;
			try {
				quickPayParams = NotifyQuickPayParams.fromXml(callBackMsg.toString());
			} catch (Exception e) {
				logger.info("快钱异步回调 | 消息体xml转换实体发生异常", e);
				throw new YYPayException(PayRspCodeEnum.PAY_CODE_PAY_FAIL.getValue(), "快钱异步回调 | 消息体xml转换实体发生异常");
			}

			// 验签
			signatureVerify(callBackMsg, quickPayParams.getTxnMsgContent().getExternalRefNumber());

			// 构造响应实体类
			NotifyQuickPayContent quickPayContent = new NotifyQuickPayContent();
			TxnMsgContent txnMsgContentReq = quickPayParams.getTxnMsgContent();

			TxnMsgContent txnMsgContentRsp = new TxnMsgContent();
			txnMsgContentRsp.setTxnType("TR4");
			txnMsgContentRsp.setMerchantId(txnMsgContentReq.getMerchantId());
			txnMsgContentRsp.setTerminalId(txnMsgContentReq.getTerminalId());
			txnMsgContentRsp.setRefNumber(txnMsgContentReq.getRefNumber());
			quickPayContent.setTxnMsgContent(txnMsgContentRsp);

			logger.info("快钱异步回调 | 响应报文：{}", quickPayContent.toXml());

			// 设置成功的结果
			content.setResultCode(PayRspCodeEnum.SUCCESS.getValue());
			content.setResultMsg("异步回调成功");

			content.setPayOrderId(txnMsgContentReq.getExternalRefNumber());
			content.setSerialNo(txnMsgContentReq.getRefNumber());
			content.setRspContent(quickPayContent.toXml());
		} catch (YYPayException e) {
			logger.info("快钱异步回调 -发生异常：|{}", e.getMessage());
			content.setResultCode(e.getCode());
			content.setResultMsg(e.getMessage());
		} catch (Exception e) {
			logger.info("快钱异步回调 -发生异常：|{}", e);
			content.setResultCode(PayRspCodeEnum.PAY_CODE_PAY_FAIL.getValue());
			content.setResultMsg("异步回调发生异常");
		}

		return content;
	}

	/**
	 * 快钱验签
	 * 
	 * @author xiemh
	 * @date 2017-04-21 15:48:57
	 * @since v1.0.0
	 * @param callBackMsg
	 * @param quickPayParams
	 * @throws Exception
	 */
	private void signatureVerify(StringBuilder callBackMsg, String orderId) throws Exception {
		boolean isVerify = false;
		String pattern = "<signature>(.[^<]*)</signature>";
		String signature = null;
		String sign = null;
		try {
			// 处理签名格式
			Matcher matcher = Pattern.compile(pattern).matcher(callBackMsg);
			if (matcher.find()) {
				signature = matcher.group(0);
				sign = matcher.group(1);
			}
			String signValue = callBackMsg.toString();
			if (signature != null) {
				signValue = signValue.replace(signature, "");
			}
			logger.info("快钱异步回调 | 签名认证：{}", sign);
			logger.info("快钱异步回调 | 签名报文：{}", signValue);

			// 根据订单号得到商户配置，并验签
			PayBusiIdVO payOrderIdVo = CommonIdUtils.getPayBusiIdVo(orderId);

			QuickPayConstant merchantInfo = quickPayInfoUtil.getMerchantInfo(QuickPayConstant.class, payOrderIdVo.getMerchantCode(),
					PaymentEnum.QUICK_PAY, PayTypeEnum.PAY, PayModeEnum.AUTH_PAY);

			isVerify = QuickPayEncodeCerUtil.enCodeByCer(merchantInfo.getMgrcerPath(), signValue, sign);
		} catch (SignatureException e) {
			logger.info("快钱异步回调 | 验签发生异常", e);
			throw new YYPayException(PayRspCodeEnum.PAY_CODE_CHECK_SIGN_FAIL.getValue(), "快钱异步回调 | 验签发生异常");
		}

		if (!isVerify) { // 如果校验不通过
			throw new YYPayException(PayRspCodeEnum.PAY_CODE_CHECK_SIGN_FAIL.getValue(), "快钱异步回调 | 验签失败");
		}
	}

	@Override
	public WebFormYYContent<PayWebFormContent> transformWebForm(WebFormYYParams req) throws Exception {
		WebFormYYContent<PayWebFormContent> content = new WebFormYYContent<PayWebFormContent>();
		PayWebFormContent payWebFormContent = new PayWebFormContent();

		payWebFormContent.setPayOrderId(req.getPayOrderId());
		//payWebFormContent.setUserIp(req.getUserIp());
		payWebFormContent.setMerchantCode(req.getMerchantCode());
		payWebFormContent.setMerchantCode(req.getMerchantCode());
		payWebFormContent.setPaymentCode(req.getPaymentCode());
		// payWebFormContent.setOrderTime(req.getOrderTime());
		// payWebFormContent.setExpireTime(req.getExpireTime());
		// payWebFormContent.setTerminal(req.getTerminal());
		// payWebFormContent.setAmount(req.getAmount());
		// payWebFormContent.setName(req.getName());
		// payWebFormContent.setIdNo(req.getIdNo());
		// payWebFormContent.setCardNo(req.getCardNo());
		// payWebFormContent.setBankName(req.getBankName());

		payWebFormContent.setSign(payWebFormContent.sign(payConstants.getSignKey()));

		QuickPayConstant merchantInfo = quickPayInfoUtil.getMerchantInfo(QuickPayConstant.class, req.getMerchantCode(), PaymentEnum.QUICK_PAY,
				PayTypeEnum.PAY, PayModeEnum.AUTH_PAY);

		content.setForm(payWebFormContent);
		// content.setUrl(merchantInfo.getActionUrl());
		content.setUrl(payConstants.getCounterUrl());
		content.setReturnUrl(merchantInfo.getReturnUrl());
		content.setNotifyUrl(merchantInfo.getNotifyUrl());
		return content;
	}

	@Override
	public OrderReturnContent transformPayOrderReturn(HttpServletRequest request) throws Exception {
		StringBuilder sb = new StringBuilder();
		try {
			try (BufferedReader in = new BufferedReader(new InputStreamReader(request.getInputStream()))) {
				String line = null;
				while ((line = in.readLine()) != null) {
					sb.append(line);
				}
				PayReturnParams payReturnParams = JacksonUtil.nonullMapper.fromJson(sb.toString(), PayReturnParams.class);
				if (payReturnParams == null) {
					throw new YYPayException(RspCodeEnum.COMMON_ERROR_NO_SIGN_AUTHENTICATION.getValue(), "请求参数为空");
				}
				OrderReturnContent orderReturnContent = new OrderReturnContent();
				orderReturnContent.setResultCode(payReturnParams.getResultCode());
				orderReturnContent.setResultMsg(payReturnParams.getResultMsg());
				orderReturnContent.setPayOrderId(payReturnParams.getPayOrderId());
				orderReturnContent.setSerialNo(payReturnParams.getSerialNo());
				return orderReturnContent;
			}
		} catch (RuntimeException e) {
			logger.error("【pay】【FUIOU】同步响应处理失败。returnContent：{}", sb.toString(), e);
			throw new YYPayException(PayRspCodeEnum.COMMON_ERROR_UNKNOWN_EXCEPTION.getValue(), "异步通知处理失败");
		}
	}

	@Override
	public PayoutOrderYYContent payoutOrder(PayoutOrderYYParams req) throws Exception {
		throw new NotImplementedException();
	}

	@Override
	public PayoutBatchOrderYYContent payoutBatchOrder(PayoutBatchOrderYYParams req) throws Exception {
		throw new NotImplementedException();
	}

	@Override
	public QueryBatchPayoutOrderYYContent queryBatchPayoutOrder(QueryBatchPayoutOrderYYParams req) throws Exception {
		throw new NotImplementedException();
	}

	@Override
	public QueryBatchPayoutOrderCheckYYContent batchPayoutOrderCheck(QueryBatchPayoutOrderCheckYYParams req) throws Exception {
		throw new NotImplementedException();
	}

	@Override
	public QueryCardBinContent queryCardBin(QueryCardBinParams req) throws Exception {
		throw new NotImplementedException();
	}

	@Override
	public OrderNotifyContent transformPayoutOrderNotify(HttpServletRequest request) throws Exception {
		throw new NotImplementedException("快钱支付不支持");
	}

	@Override
	public QueryPayoutOrderYYContent queryPayoutOrder(QueryPayoutOrderYYParams req) throws Exception {
		throw new NotImplementedException("快钱支付不支持");
	}

	// @Override
	// public MerchantConfigExtContent queryMerchantConfigExt(String merchantCode, PayTypeEnum paytType, PayModeEnum payMode) throws Exception {
	// QuickPayConstant constant = quickPayInfoService.getMerchantInfo(merchantCode, PaymentEnum.QUICK_PAY, paytType, payMode);
	// if (constant == null) {
	// throw new YYException(PayRspCodeEnum.COMMON_ERROR_OBJECT_NOT_FOUND, "没有找到相关商户配置信息");
	// }
	//
	// MerchantConfigExtContent extContent = new MerchantConfigExtContent();
	// extContent.setReturnUrl(constant.getReturnUrl());
	// extContent.setNotifyUrl(constant.getNotifyUrl());
	//
	// return extContent;
	// }
}
